//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_sprit_api_serv

import (
	"context"

	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/issue_dao"
	"atomgit.com/openlinksaas-org/api-server/utils"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_issue_api"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_sprit_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

type ProjectSpritApiImpl struct {
	project_sprit_api.UnimplementedProjectSpritApiServer
}

func (apiImpl *ProjectSpritApiImpl) Create(ctx context.Context, req *project_sprit_api.CreateRequest) (*project_sprit_api.CreateResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_sprit_api.CreateResponse{
			Code:   project_sprit_api.CreateResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_sprit_api.CreateResponse{
			Code:   project_sprit_api.CreateResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_sprit_api.CreateResponse{
			Code:   project_sprit_api.CreateResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if !(projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin) {
		return &project_sprit_api.CreateResponse{
			Code:   project_sprit_api.CreateResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	spritId := uuid.NewString()

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)
	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = issue_dao.SpritDao.Insert(sessCtx, &issue_dao.SpritInfoDbItem{
			SpritId:      spritId,
			ProjectId:    req.ProjectId,
			SummaryState: uint32(project_sprit_api.SUMMARY_STATE_SUMMARY_COLLECT),
		})
		if err != nil {
			return nil, err
		}
		err = issue_dao.SpritStateDao.Insert(sessCtx, &issue_dao.SpritStateDbItem{
			SpritId:        spritId,
			TaskCount:      0,
			TaskCountDirty: false,
			BugCount:       0,
			BugCountDirty:  false,
		})
		if err != nil {
			return nil, err
		}
		return &project_sprit_api.CreateResponse{
			Code:    project_sprit_api.CreateResponse_CODE_OK,
			SpritId: spritId,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*project_sprit_api.CreateResponse), nil
}

func (apiImpl *ProjectSpritApiImpl) listState(ctx context.Context, projectId string, spritIdList []string) ([]*issue_dao.SpritStateDbItem, error) {
	stateItemList, err := issue_dao.SpritStateDao.ListById(ctx, spritIdList)
	if err != nil {
		return nil, err
	}
	for _, stateItem := range stateItemList {
		if stateItem.BugCountDirty {
			count, err := issue_dao.IssueDao.Count(ctx, projectId, &project_issue_api.ListParam{
				FilterByIssueType: true,
				IssueType:         project_issue_api.ISSUE_TYPE_ISSUE_TYPE_BUG,
				FilterBySpritId:   true,
				SpritIdList:       []string{stateItem.SpritId},
			}, []string{})
			if err != nil {
				return nil, err
			}
			err = issue_dao.SpritStateDao.SetBugCount(ctx, stateItem.SpritId, count)
			if err != nil {
				return nil, err
			}
			stateItem.BugCount = count
			stateItem.BugCountDirty = false
		}
		if stateItem.TaskCountDirty {
			count, err := issue_dao.IssueDao.Count(ctx, projectId, &project_issue_api.ListParam{
				FilterByIssueType: true,
				IssueType:         project_issue_api.ISSUE_TYPE_ISSUE_TYPE_TASK,
				FilterBySpritId:   true,
				SpritIdList:       []string{stateItem.SpritId},
			}, []string{})
			if err != nil {
				return nil, err
			}
			err = issue_dao.SpritStateDao.SetTaskCount(ctx, stateItem.SpritId, count)
			if err != nil {
				return nil, err
			}
			stateItem.TaskCount = count
			stateItem.TaskCountDirty = false
		}
	}
	return stateItemList, nil
}

func (apiImpl *ProjectSpritApiImpl) Get(ctx context.Context, req *project_sprit_api.GetRequest) (*project_sprit_api.GetResponse, error) {
	emptyInfo := &project_sprit_api.SpritInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_sprit_api.GetResponse{
			Code:   project_sprit_api.GetResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
			Info:   emptyInfo,
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_sprit_api.GetResponse{
			Code:   project_sprit_api.GetResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
			Info:   emptyInfo,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_sprit_api.GetResponse{
			Code:   project_sprit_api.GetResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
			Info:   emptyInfo,
		}, nil
	} else if err != nil {
		return nil, err
	}

	spritItem, err := issue_dao.SpritDao.Get(ctx, req.ProjectId, req.SpritId)
	if err != nil {
		return &project_sprit_api.GetResponse{
			Code:   project_sprit_api.GetResponse_CODE_NO_SPRIT,
			ErrMsg: "迭代不存在",
			Info:   emptyInfo,
		}, nil
	}
	stateItemList, err := apiImpl.listState(ctx, req.ProjectId, []string{req.SpritId})
	if err != nil {
		return nil, err
	}

	taskCount := uint32(0)
	bugCount := uint32(0)
	if len(stateItemList) > 0 {
		taskCount = stateItemList[0].TaskCount
		bugCount = stateItemList[0].BugCount
	}

	info := spritItem.ToSpritInfo(taskCount, bugCount)

	return &project_sprit_api.GetResponse{
		Code: project_sprit_api.GetResponse_CODE_OK,
		Info: info,
	}, nil
}
